package com.liuqi.knet.util;

import java.nio.charset.Charset;

/**
 * byte & 数值转换
 *
 * @author liuqi
 * @date 2024/12/13 14:37
 **/
public final class Bytes {

    /**
     * 16进制字符串转二进制字节数组
     *
     * @param hexEncodedBinary
     * @return
     */
    public static byte[] hexStringToBytes(String hexEncodedBinary) {
        if (hexEncodedBinary.length() % 2 == 0) {
            char[] sc = hexEncodedBinary.toCharArray();
            byte[] ba = new byte[sc.length / 2];
            for (int i = 0; i < ba.length; i++) {
                int nibble0 = Character.digit(sc[i * 2], 16);
                int nibble1 = Character.digit(sc[i * 2 + 1], 16);
                if (nibble0 == -1 || nibble1 == -1){
                    throw new IllegalArgumentException(
                            "Hex-encoded binary string contains an invalid hex digit in '"+sc[i * 2]+sc[i * 2 + 1]+"'");
                }
                ba[i] = (byte) ((nibble0 << 4) | nibble1);
            }
            return ba;
        } else {
            throw new IllegalArgumentException(
                    "Hex-encoded binary string contains an uneven no. of digits");
        }
    }

    /**
     * 字节数组转16进制字符串
     *
     * @param bytes
     * @return
     */
    public static String bytesToHexString(byte[] bytes) {
        StringBuilder buf = new StringBuilder();
        String tmp = null;
        for (byte b : bytes) {
            // // 将每个字节与0xFF进行与运算，然后转化为10进制，然后借助于Integer再转化为16进制
            tmp = Integer.toHexString(0xFF & b);
            if (tmp.length() == 1) {    // 每个字节8为，转为16进制标志，2个16进制位
                tmp = "0" + tmp;
            }
            buf.append(tmp);
        }
        return buf.toString();
    }

    public static byte[] bytes2bytes(byte[] b) {
        byte[] bytes = new byte[b.length];
        bytes2bytes(b, bytes, 0);
        return bytes;
    }

    public static void bytes2bytes(byte[] b, byte[] bytes, int off) {
        for (int i = 0; i < b.length; i++) {
            bytes[i + off] = b[i];
        }
    }

    public static byte[] byte2bytes(byte n) {
        byte[] bytes = new byte[1];
        byte2bytes(n, bytes, 0);
        return bytes;
    }

    public static void byte2bytes(byte n, byte[] b, int off) {
        b[off] = n;
    }

    public static byte[] short2bytes(short s) {
        byte[] bytes = new byte[2];
        short2bytes(s, bytes, 0);
        return bytes;
    }

    public static void short2bytes(short s, byte[] b, int off) {
        b[off + 1] = (byte) s;
        b[off] = (byte) (s >>> 8);
    }

    public static byte[] int2bytes(int i) {
        byte[] bytes = new byte[4];
        int2bytes(i, bytes, 0);
        return bytes;
    }

    public static void int2bytes(int i, byte[] b, int off) {
        b[off + 3] = (byte) i;
        b[off + 2] = (byte) (i >>> 8);
        b[off + 1] = (byte) (i >>> 16);
        b[off] = (byte) (i >>> 24);
    }

    public static byte[] long2bytes(long l) {
        byte[] bytes = new byte[8];
        long2bytes(l, bytes, 0);
        return bytes;
    }

    public static void long2bytes(long l, byte[] b, int off) {
        b[off + 7] = (byte) l;
        b[off + 6] = (byte) (l >>> 8);
        b[off + 5] = (byte) (l >>> 16);
        b[off + 4] = (byte) (l >>> 24);
        b[off + 3] = (byte) (l >>> 32);
        b[off + 2] = (byte) (l >>> 40);
        b[off + 1] = (byte) (l >>> 48);
        b[off] = (byte) (l >>> 56);
    }

    public static void string2bytes(String s, byte[] b, int off, int len) {
        byte[] sb = s.getBytes();
        for (int i = 0; i < len; i++) {
            if (sb.length > i) {
                b[off + i] = sb[i];
            } else {
                b[off + i] = 0; // 位数不足, 后置补0
            }
        }
    }

    public static byte bytes2byte(byte[] b, int off) {
        return b[off];
    }

    public static short bytes2short(byte[] b, int off) {
        return (short) (((b[off + 1] & 0xFF) << 0) +
                ((b[off]) << 8));
    }

    public static int bytes2int(byte[] b, int off) {
        return ((b[off + 3] & 0xFF) << 0) +
                ((b[off + 2] & 0xFF) << 8) +
                ((b[off + 1] & 0xFF) << 16) +
                ((b[off]) << 24);
    }

    public static long bytes2int_unit32(byte[] b, int off) {
        long value = b[3 + off] & 0xFF;
        value |= (b[2 + off] << 8) & 0xFFFF;
        value |= (b[1 + off] << 16) & 0xFFFFFF;
        value |= (b[0 + off] << 24) & 0xFFFFFFFF;
        return value;
    }

    public static long bytes2long(byte[] b, int off) {
        return ((b[off + 7] & 0xFFL) << 0) +
                ((b[off + 6] & 0xFFL) << 8) +
                ((b[off + 5] & 0xFFL) << 16) +
                ((b[off + 4] & 0xFFL) << 24) +
                ((b[off + 3] & 0xFFL) << 32) +
                ((b[off + 2] & 0xFFL) << 40) +
                ((b[off + 1] & 0xFFL) << 48) +
                (((long) b[off]) << 56);
    }

    public static String bytes2String(byte[] b, int off, int len) {
        return new String(b, off, len);
    }

    public static String bytes2String(byte[] b, int off, int len, Charset charset) {
        return new String(b, off, len, charset);
    }

}
